/**************************************************************************** 
* 
* Copyright (c) 2023  C*Core -   All Rights Reserved  
* 
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED, 
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* 
* PROJECT     : CCFC2011BC           
* DESCRIPTION : CCFC2011BC icu low level drivers code 
* HISTORY     : Initial version.
* @file     icu_lld.c
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/
#include "siul_lld.h"
#include "emios_lld.h"
#include "IntcInterrupts.h"

/*===========================================================================*/
/* Driver local definitions.                                                 */
/*===========================================================================*/

/*******************************************************************************
 * @brief      ICU IRQ handler.
 * @param[in]  icup      pointer to the @p ICUDriver object
 *             icu_interrupt_group_t group, 
 *             uint8_t channel
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
void ICU_LLD_Serve_Interrupt(ICUDriver *icudriver, icu_interrupt_group_t group, uint8_t channel)
{
    uint8_t ch_val;
    uint16_t period, width;
    /* interrupt flag */
    uint32_t gfr = icudriver->emiosp->GFR.R;

    ch_val = channel;

    /* get which channel interrupt */
    if ((gfr & (uint32_t)group) != (uint32_t)group)
    {
        ch_val++;
    }

    if ((gfr & (1UL << ch_val)) != 0U)
    {
        uint32_t sr = icudriver->emiosp->CH[ch_val].CSR.R;

        switch (icudriver->config->hw_mode)
        {
            case ICU_INPUT_SINGLE_ACTION_MODE:
                if (((sr & EMIOSS_OVFL) != 0U) && (icudriver->config->config_saic.overflow_cb != NULL))
                { //  overflow had occurred
                    icudriver->emiosp->CH[ch_val].CSR.R |= EMIOSS_OVFLC;  //  write 1 to clear flag
                    (icudriver)->config->config_saic.overflow_cb(icudriver);
                }

                if ((sr & EMIOSS_FLAG) != 0U)
                {
                    icudriver->emiosp->CH[ch_val].CSR.R |= EMIOSS_FLAGC;

                    switch (icudriver->config->config_saic.usermode)
                    {
                        case ICU_USER_MODE_EDGE_COUNTER:
                            icudriver->data.saic_data.edge_numbers[ch_val]++;
                            (icudriver)->config->config_saic.edge_count_cb(icudriver);
                            break;
                        case ICU_USER_MODE_TIME_STAMP:
                            icudriver->data.saic_data.time_stamp[ch_val] = icudriver->emiosp->CH[ch_val].CADR.B.A;
                            (icudriver)->config->config_saic.time_stamp_cb(icudriver);
                            break;
                        case ICU_USER_MODE_WIDTH_PERIOD_MEASUREMENT:
                            if ((icudriver->emiosp->CH[ch_val].CSR.B.UCIN == 1U) && \
                                (icudriver->config->config_saic.width_cb != NULL))
                            {
                                icudriver->data.saic_data.pe.a2_2 = icudriver->emiosp->CH[ch_val].CADR.B.A;
                                width = (icudriver->data.saic_data.pe.a2_2 - icudriver->data.saic_data.pe.a2_1);
                                icudriver->data.saic_data.width[ch_val] = width;
                                (icudriver)->config->config_saic.width_cb(icudriver);
                            }

                            if ((icudriver->emiosp->CH[ch_val].CSR.B.UCIN == 0UL) && \
                                (icudriver->config->config_saic.period_cb != NULL))
                            {
                                icudriver->data.saic_data.pe.a2_3 = icudriver->emiosp->CH[ch_val].CADR.B.A;
                                period = (icudriver->data.saic_data.pe.a2_3 - icudriver->data.saic_data.pe.a2_1);
                                icudriver->data.saic_data.period[ch_val] = period;
                                (icudriver)->config->config_saic.period_cb(icudriver);
                                icudriver->data.saic_data.pe.a2_1 = icudriver->data.saic_data.pe.a2_3;
                            }
                            break;

                        default:
                            break;
                    }
                }
                break;

            case ICU_INPUT_PULSE_WIDTH_MEASUREMENT_MODE:
                    if (((sr & EMIOSS_OVFL) != 0U) && (icudriver->config->config_ipwm.overflow_cb != NULL))
                    { //  overflow had occurred
                        icudriver->emiosp->CH[ch_val].CSR.R |= EMIOSS_OVFLC;  //  write 1 to clear flag
                        (icudriver)->config->config_ipwm.overflow_cb(icudriver);
                    }

                    if ((sr & EMIOSS_FLAG) != 0U)
                    {
                        icudriver->emiosp->CH[ch_val].CSR.R |= EMIOSS_FLAGC;
                        icudriver->data.ipwm_data.time_stamp2[ch_val] = icudriver->emiosp->CH[ch_val].CADR.B.A;
                        icudriver->data.ipwm_data.time_stamp1[ch_val] = icudriver->emiosp->CH[ch_val].CBDR.B.B;
                        if (icudriver->config->config_ipwm.ipwm_cb != NULL)
                        {
                            (icudriver)->config->config_ipwm.ipwm_cb(icudriver);
                        }
                    }
                break;

            case ICU_INPUT_PERIOD_WIDTH_MEASUREMENT_MODE:
                    if (((sr & EMIOSS_OVFL) != 0U) && (icudriver->config->config_ipm.overflow_cb != NULL))
                    { //  overflow had occurred
                        icudriver->emiosp->CH[ch_val].CSR.R |= EMIOSS_OVFLC;  //  write 1 to clear flag

                        (icudriver)->config->config_ipm.overflow_cb(icudriver);
                    }

                    if ((sr & EMIOSS_FLAG) != 0U)
                    {
                        icudriver->emiosp->CH[ch_val].CSR.R |= EMIOSS_FLAGC;
                        icudriver->data.ipm_data.time_stamp2[ch_val] = icudriver->emiosp->CH[ch_val].CADR.B.A;
                        icudriver->data.ipm_data.time_stamp1[ch_val] = icudriver->emiosp->CH[ch_val].CBDR.B.B;
                        if (icudriver->config->config_ipm.ipw_cb != NULL)
                        {
                            (icudriver)->config->config_ipm.ipw_cb(icudriver);
                        }
                    }
                break;
            default:
                break;
        }

        if ((sr & EMIOSS_OVR) != 0U)
        {
            icudriver->emiosp->CH[ch_val].CSR.R |= EMIOSS_OVRC;
        }
    }
}

/*===========================================================================*/
/* Driver exported functions.                                                */
/*===========================================================================*/
/*******************************************************************************
 * @brief      Low level ICU driver initialization.
 * @param[in]  icudriver        PWMD_N
 *             EMIOS_tag * emios_base_address
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
static void ICU_LLD_DeInit(ICUDriver * icudriver, volatile struct EMIOS_tag * emios_base_address)
{
    icudriver->emiosp = emios_base_address;

    emios_base_address->MCR.R = 0;
    emios_base_address->OUDR.R = 0;
    emios_base_address->UCDIS.R = 0;

    icudriver->emiosp = NULL;
    icudriver->ch_num.R = 0;
    icudriver->sys_clock = 0;
    icudriver->emios_prescale = 0;
    icudriver->config = NULL;
}

/*******************************************************************************
 * @brief      PWM low level driver deinitialization
 * @param[in]  pwmdriver    PWMD_N
 *             emios_base_address     EMIOS_0 or EMIOS_1
 *             emios_prescale    1 - 256
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
void ICU_LLD_Init(ICUDriver * icudriver, volatile struct EMIOS_tag * emios_base_address, uint8_t emios_prescale)
{
    uint32_t i;

    ICU_LLD_DeInit(icudriver, emios_base_address);

    /* icudriver Init*/
    icudriver->emiosp = emios_base_address;
    icudriver->ch_num.R = 0;
    icudriver->sys_clock = GetSystemClock();
    icudriver->emios_prescale = emios_prescale;

    for (i = 0U; i < 32U; i++)
    {
        icudriver->data.saic_data.edge_numbers[i] = 0;
        icudriver->data.saic_data.time_stamp[i] = 0;
        icudriver->data.saic_data.width[i] = 0;
        icudriver->data.saic_data.pe.a2_1 = 0;
        icudriver->data.saic_data.pe.a2_2 = 0;
        icudriver->data.saic_data.pe.a2_3 = 0;
        icudriver->data.saic_data.period[i] = 0;
        icudriver->data.ipwm_data.time_stamp1[i] = 0;
        icudriver->data.ipwm_data.time_stamp2[i]  = 0;
        icudriver->data.ipwm_data.pulse_width_numbers[i] = 0;
        icudriver->data.ipm_data.time_stamp1[i] = 0;
        icudriver->data.ipm_data.time_stamp2[i] = 0;
        icudriver->data.ipm_data.period_numbers[i] = 0;
    }

    icudriver->emiosp->MCR.R = 0;
    icudriver->emiosp->MCR.R &= ~EMIOSMCR_MDIS;
    icudriver->emiosp->MCR.R &= ~EMIOSMCR_GPREN;
    icudriver->emiosp->MCR.R |= EMIOSMCR_GPRE(emios_prescale - 1UL);
    icudriver->emiosp->MCR.R |= EMIOSMCR_GPREN;
    icudriver->emiosp->MCR.B.GTBE = 1U;
    icudriver->emiosp->OUDR.R = 0;
    icudriver->emiosp->UCDIS.R = 0xFFFFFFFFU;
}

/*******************************************************************************
 * @brief      ICU_LLD_UC_Channel_DeInit
 * @param[in]  const ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
static void ICU_LLD_UC_Channel_DeInit(const ICUDriver * icudriver, uint8_t channel)
{
    /* Channel enables to write registers.*/
    icudriver->emiosp->UCDIS.R &= ~(1UL << channel);

    /*DeInit all used registers*/
    icudriver->emiosp->CH[channel].CCR.R = 0;
    icudriver->emiosp->CH[channel].CADR.R = 0;
    icudriver->emiosp->CH[channel].CBDR.R = 0;
    icudriver->emiosp->CH[channel].CCNTR.R = 0;
    icudriver->emiosp->CH[channel].CSR.R = 0;
}

/*******************************************************************************
 * @brief      ICU_LLD_UC_Channel_Init
 * @param[in]  ICUDriver * icudriver, uint8_t channel, ICUConfig_t * icuconfig
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
void ICU_LLD_UC_Channel_Init(ICUDriver * icudriver, uint8_t channel, ICUConfig_t * icuconfig)
{
    icudriver->ch_num.R |= 1UL << channel;
    icudriver->config = icuconfig;

    /*DeInit all used registers*/
    ICU_LLD_UC_Channel_DeInit(icudriver, channel);

    /* Channel enables to write registers.*/
    icudriver->emiosp->UCDIS.R &= ~(1UL << channel);

    /* Set UC mode.*/
    switch (icudriver->config->hw_mode)
    {
        case ICU_INPUT_SINGLE_ACTION_MODE:
            /* Set UC clock prescaler and control register.*/
            icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_UCPREN;

            /* selet clock source.*/
            switch (icudriver->config->config_saic.clock_bus)
            {
                case ICU_INTERNAL_COUNTER:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_INTERNAL_COUNTER);
                    break;
                case ICU_COUNTER_BUS_A:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_COUNTER_BUS_A);
                    break;
                case ICU_COUNTER_BUS_2:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_COUNTER_BUS_2);
                    break;
                default:
                    break;
            }

            icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_UCPRE(icudriver->config->config_saic.uc_prescale);
            icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_UCPREN;

            /* Set edge_polarity.*/
            switch (icudriver->config->config_saic.edge_polarity)
            {
                case FALLING_EDGE:
                    icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_EDSEL;
                    icudriver->emiosp->CH[channel].CCR.R &= EMIOSC_EDPOL;
                    break;
                case RISING_EDGE:
                    icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_EDSEL;
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_EDPOL;
                    break;
                case BOTH_EDGE:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_EDSEL;
                    break;
                default:
                    break;
            }

            icudriver->emiosp->CH[channel].CCR.R |= EMIOS_CCR_MODE_SAIC;
            break;
        case ICU_INPUT_PULSE_WIDTH_MEASUREMENT_MODE:
            /* Set UC clock prescaler and control register.*/
            icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_UCPREN;
            /* selet clock source.*/
            switch (icudriver->config->config_ipwm.clock_bus)
            {
                case ICU_INTERNAL_COUNTER:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_INTERNAL_COUNTER);
                    break;
                case ICU_COUNTER_BUS_A:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_COUNTER_BUS_A);
                    break;
                case ICU_COUNTER_BUS_2:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_COUNTER_BUS_2);
                    break;
                default:
                    break;
            }

            icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_UCPRE(icudriver->config->config_ipwm.uc_prescale);
            icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_UCPREN;

            /* Set edge_polarity.*/
            switch (icudriver->config->config_ipwm.edge_polarity)
            {
                case FALLING_EDGE:
                    icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_EDSEL;
                    icudriver->emiosp->CH[channel].CCR.R &= EMIOSC_EDPOL;
                    break;
                case RISING_EDGE:
                    icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_EDSEL;
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_EDPOL;
                    break;
                default:
                    break;
            }

            icudriver->emiosp->CH[channel].CCR.R |= EMIOS_CCR_MODE_IPWM;
            break;

        case ICU_INPUT_PERIOD_WIDTH_MEASUREMENT_MODE:
            /* Set UC clock prescaler and control register.*/
            icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_UCPREN;
            /* selet clock source.*/
            switch (icudriver->config->config_ipm.clock_bus)
            {
                case ICU_INTERNAL_COUNTER:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_INTERNAL_COUNTER);
                    break;

                case ICU_COUNTER_BUS_A:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_COUNTER_BUS_A);
                    break;

                case ICU_COUNTER_BUS_2:
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_BSL(EMIOS_BSL_COUNTER_BUS_2);
                    break;

                default:
                    break;
            }

            icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_UCPRE(icudriver->config->config_ipm.uc_prescale);
            icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_UCPREN;

            /* Set edge_polarity.*/
            switch (icudriver->config->config_ipm.edge_polarity)
            {
                case FALLING_EDGE:
                    icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_EDSEL;
                    icudriver->emiosp->CH[channel].CCR.R &= EMIOSC_EDPOL;
                    break;
                case RISING_EDGE:
                    icudriver->emiosp->CH[channel].CCR.R &= ~EMIOSC_EDSEL;
                    icudriver->emiosp->CH[channel].CCR.R |= EMIOSC_EDPOL;
                    break;
                default:
                    break;
            }

            icudriver->emiosp->CH[channel].CCR.R |= EMIOS_CCR_MODE_IPM;

            break;
        default:
            break;
    }

    icudriver->emiosp->CH[channel].CCNTR.R  = 0;

     /* Channel disables.*/
    icudriver->emiosp->UCDIS.R |= (1UL << channel);
}

/*******************************************************************************
 * @brief      ICU_LLD_GPIO_Enable
 * @param[in]  const ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
static void ICU_LLD_GPIO_Enable(const ICUDriver * icudriver, uint8_t channel)
{
    if (icudriver->emiosp != &EMIOS_1)
    {
        if (channel < 12U)
        {
            SIU.PCR[channel].R = (PCR_PA1|PCR_IBE);/* assign port pad to Alt Func 1  */
        }
        else
        {
            switch (channel)
            {
                case 12:
                    SIU.PCR[PC12_PCR].R = (PCR_PA1|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 13:
                    SIU.PCR[PC13_PCR].R = (PCR_PA1|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 14:
                    SIU.PCR[PC14_PCR].R = (PCR_PA1|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 15:
                    SIU.PCR[PC15_PCR].R = (PCR_PA1|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 16:
                    SIU.PCR[PE0_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 17:
                    SIU.PCR[PE1_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 18:
                    SIU.PCR[PE2_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 19:
                    SIU.PCR[PE3_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 20:
                    SIU.PCR[PE4_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 21:
                    SIU.PCR[PE5_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 22:
                    SIU.PCR[PE6_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 23:
                    SIU.PCR[PE7_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 24:
                    SIU.PCR[PD12_PCR].R = (PCR_PA2|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 25:
                    SIU.PCR[PD13_PCR].R = (PCR_PA1|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 26:
                    SIU.PCR[PD14_PCR].R = (PCR_PA2|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 27:
                    SIU.PCR[PD15_PCR].R = (PCR_PA2|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 28:
                    SIU.PCR[PA12_PCR].R = (PCR_PA1|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 29:
                    SIU.PCR[PA13_PCR].R = (PCR_PA2|PCR_IBE);    /* assign port pad to Alt Func 1  and input*/
                    break;
                case 30:
                    SIU.PCR[PB0_PCR].R = (PCR_PA2|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                case 31:
                    SIU.PCR[PB1_PCR].R = (PCR_PA1|PCR_IBE);     /* assign port pad to Alt Func 1  and input*/
                    break;
                default:
                    break;
            }
        }
    }
    else
    {
        switch (channel)
        {
            case 0:
                SIU.PCR[PG14_PCR].R = PCR_PA1;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 1:
                SIU.PCR[PG15_PCR].R = PCR_PA1;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 2:
                SIU.PCR[PH0_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 3:
                SIU.PCR[PH1_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 4:
                SIU.PCR[PH2_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 5:
                SIU.PCR[PH3_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 6:
                SIU.PCR[PH4_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 7:
                SIU.PCR[PH5_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 8:
                SIU.PCR[PH6_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 9:
                SIU.PCR[PH7_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 10:
                SIU.PCR[PH8_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 11:
                SIU.PCR[PG2_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 12:
                SIU.PCR[PG3_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 13:
                SIU.PCR[PG4_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 14:
                SIU.PCR[PG5_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 15:
                SIU.PCR[PG6_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 16:
                SIU.PCR[PG7_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 17:
                SIU.PCR[PG8_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 18:
                SIU.PCR[PG9_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 19:
                SIU.PCR[PE12_PCR].R = PCR_PA2;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 20:
                SIU.PCR[PE13_PCR].R = PCR_PA2;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 21:
                SIU.PCR[PE14_PCR].R = PCR_PA2;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 22:
                SIU.PCR[PE15_PCR].R = PCR_PA2;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 23:
                SIU.PCR[PG0_PCR].R = PCR_PA2;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 24:
                SIU.PCR[PG1_PCR].R = PCR_PA2;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 25:
                SIU.PCR[PF12_PCR].R = PCR_PA1;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 26:
                SIU.PCR[PF13_PCR].R = PCR_PA1;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 27:
                SIU.PCR[PF14_PCR].R = PCR_PA2;    /* assign port pad to Alt Func 1  and input*/
                break;
            case 28:
                SIU.PCR[PI4_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 29:
                SIU.PCR[PI5_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 30:
                SIU.PCR[PI6_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            case 31:
                SIU.PCR[PI7_PCR].R = PCR_PA1;     /* assign port pad to Alt Func 1  and input*/
                break;
            default:
                break;
        }
    }
}

/*******************************************************************************
 * @brief      ICU_LLD_UC_Channel_Enable
 * @param[in]  const ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
void ICU_LLD_UC_Channel_Enable(const ICUDriver * icudriver, uint8_t channel)
{
    //ICU_LLD_GPIO_Enable(icudriver, channel);

    /* Channel enables.*/
    icudriver->emiosp->UCDIS.R &= ~(1UL << channel);

    /* Clear pending IRQs (if any).*/
    icudriver->emiosp->CH[channel].CSR.R = EMIOSS_OVRC |
        EMIOSS_OVFLC | EMIOSS_FLAGC;

    /* Active interrupts.*/
    icudriver->emiosp->CH[channel].CCR.B.FEN = 1U;
}

/*******************************************************************************
 * @brief      ICU_LLD_UC_Channel_Disable
 * @param[in]  const ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
void ICU_LLD_UC_Channel_Disable(const ICUDriver * icudriver, uint8_t channel)
{
    /* Clear pending IRQs (if any).*/
    icudriver->emiosp->CH[channel].CSR.R = EMIOSS_OVRC |
        EMIOSS_OVFLC | EMIOSS_FLAGC;

    /* disable interrupts.*/
    icudriver->emiosp->CH[channel].CCR.B.FEN = 0U;

    /* Channel disable.*/
    icudriver->emiosp->UCDIS.R |= (1UL << channel);

    /* Channel disable.*/
    icudriver->emiosp->UCDIS.R |= (1UL << channel);
}

/*******************************************************************************
 * @brief      ICU_LLD_GetFrequency
 * @param[in]  const ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     None
 * @notapi 
 *******************************************************************************/
uint32_t ICU_LLD_GetFrequency(const ICUDriver * icudriver, uint8_t channel)
{
    uint32_t  timer_clock, period;

    timer_clock = icudriver->sys_clock/icudriver->emios_prescale;
    period = icudriver->data.saic_data.period[channel];

    return timer_clock/period;
}

/*******************************************************************************
 * @brief      ICU_LLD_GetDutyCycle
 * @param[in]  ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     float32_t
 * @notapi 
 *******************************************************************************/
float32_t ICU_LLD_GetDutyCycle(ICUDriver * icudriver, uint8_t channel)
{
    uint16_t  width, period;
    float32_t res;

    res = (float32_t)0;

    width = icudriver->data.saic_data.width[channel];
    period = icudriver->data.saic_data.period[channel];

    if (period != 0U)
    {
        res = (((float32_t)1 - ((float32_t)width / (float32_t)period)) * (float32_t)100);
    }

    icudriver->data.saic_data.width[channel] = 0;
    icudriver->data.saic_data.period[channel] = 0 ;

    return res;
}

/*******************************************************************************
 * @brief      ICU_LLD_GetTimeElapsed
 * @param[in]  ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     float32_t
 * @notapi 
 *******************************************************************************/
uint16_t ICU_LLD_GetTimeElapsed(ICUDriver * icudriver, uint8_t channel)
{
    uint16_t  count;

    count = icudriver->data.ipwm_data.time_stamp2[channel] - \
            icudriver->data.ipwm_data.time_stamp1[channel];

    icudriver->data.ipwm_data.time_stamp2[channel] = 0;
    icudriver->data.ipwm_data.time_stamp1[channel] = 0;

    return count;
}


/*******************************************************************************
 * @brief      ICU_LLD_GetPeriodTime
 * @param[in]  ICUDriver * icudriver, uint8_t channel
 * @param[out] None
 * @retval     float32_t
 * @notapi 
 *******************************************************************************/
uint16_t ICU_LLD_GetPeriodTime(ICUDriver * icudriver, uint8_t channel)
{
    uint16_t  count;

    count = icudriver->data.ipm_data.time_stamp2[channel] - \
            icudriver->data.ipm_data.time_stamp1[channel];

    icudriver->data.ipm_data.time_stamp2[channel] = 0;
    icudriver->data.ipm_data.time_stamp1[channel] = 0;

    return count;
}

